#include "types.h"
#include "params.h"
#include "memory.h"
#include "lock.h"
#include "kobj.h"
#include "kfunc.h"
#include "util.h"
#include "pipe.h"
#define MAX_PIPE 128

struct {
    struct pipe pipes[MAX_PIPE];
    int map[MAX_PIPE]; // 0 for free;
    struct sleeplk lk; 
} pipool;

void
pipeinit () {
    bzero (&pipool, sizeof (pipool));
}

struct pipe *
alloc_pipe () {
    int i;
    struct pipe * p;
    sleep_lock (&pipool.lk);
    for (i = 0; i < MAX_PIPE; i++) {
        if (pipool.map[i] == 0) {
            pipool.map[i] = 1;
            bzero (&pipool.pipes[i], sizeof (struct pipe));
            p = &pipool.pipes[i];
            p->kbuf = kalloc ();
            p->pipsz = PGSZ;
            p->id = i;
            sleep_lock (&p->full); // 阻塞读线程
            goto found;
        }
    }
    sleep_unlock (&pipool.lk);
    return 0;
    found:
    sleep_unlock (&pipool.lk);
    return p;
}

int
free_pipe (void * ctx) {
    struct pipe * pi = (struct pipe *)ctx;
    if (!pipool.map[pi->id])
        goto error;
    pipool.map[pi->id] = 0;
    error:
    return -1;
}

int
read_pipe (struct pipe * p, void * to, unsigned int sz) {
    if (sz > p->pipsz)
        goto bad;
    int cnt = 0;
    sleep_lock (&p->full);
    for (p->r = 0; p->r < p->w; p->r++) { // p->r = p->w = w.sz
        *(char*)to = p->kbuf[p->r];
        cnt++;
    }
    sleep_unlock (&p->empty);
    return cnt;
    bad:
    return -1;
}

int
write_pipe (struct pipe * p, void * from, unsigned int sz) {
    if (sz > p->pipsz)
        goto bad;
    int cnt;
    sleep_lock (&p->empty);
    for (p->w = 0; p->w < sz; p->w++) { // p->w = w.sz
        p->kbuf[p->w] = *(char*)from;
        cnt++;
    }
    sleep_unlock (&p->full);
    return cnt;
    bad:
    return -1;
}

int
read_pipeko (struct ko * o, void * to,unsigned int sz) {
    int retval;
    retval = read_pipe ((struct pipe*) o->ctx, to, sz);
    return retval;
}

int
write_pipeko (struct ko * o, void * from,unsigned int sz) {
    int retval;
    retval = write_pipe ((struct pipe*) o->ctx, from, sz);
    return retval;
}
